package cn.vehicle.exception;

import cn.vehicle.domains.vo.Result;
import cn.vehicle.enums.StatusCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.HashMap;
import java.util.Map;

/**
 * 全局异常处理器
 * <p>
 * 统一捕获并处理系统中的各类异常，保证接口返回格式一致。
 * </p>
 *
 * <p>主要职责：</p>
 * <ul>
 *   <li>捕获自定义业务异常 {@link VehicleAccessException}；</li>
 *   <li>捕获参数校验异常 {@link MethodArgumentNotValidException} 与 {@link IllegalArgumentException}；</li>
 *   <li>捕获请求体解析异常 {@link HttpMessageNotReadableException}；</li>
 *   <li>捕获其他未处理的系统异常。</li>
 * </ul>
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {


    /**
     * 处理自定义业务异常
     *
     * @param e 自定义异常对象
     * @return 封装后的统一响应结果
     */
    @ExceptionHandler(VehicleAccessException.class)
    public Result<Void> vehicleAccessExceptionHandler(VehicleAccessException e) {
        log.error("出现业务异常", e);
        return Result.error(e.getDefineCode(), e.getMessage());
    }

    /**
     * 处理系统未知异常
     *
     * @param e 捕获的异常对象
     * @return 标准化错误响应
     */
    @ExceptionHandler(Exception.class)
    public Result<Void> exceptionHandler(Exception e) {
        // 记录完整异常堆栈，便于排查问题
        log.error("出现系统异常", e);
        return Result.error(StatusCode.SYSTEM_ERROR.getCode(), StatusCode.SYSTEM_ERROR.getMessage());
    }


    /**
     * 处理参数校验异常（如 @Valid 校验失败）
     *
     * @param e 参数验证异常
     * @return 包含字段错误信息的统一响应
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<Void> methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
        // 收集所有字段校验失败的错误信息
        Map<String, String> errors = new HashMap<>();

        e.getBindingResult().getAllErrors().forEach((error) -> {
            // 获取字段名和对应的错误提示
            String field = ((FieldError) error).getField();
            String errorMessage = error.getDefaultMessage();

            errors.put(field, errorMessage);
        });

        return Result.error(StatusCode.PARAMS_ERROR.getCode(), "请求参数验证失败" + errors);
    }

    /**
     * 处理请求体 JSON 解析异常
     *
     * @param ex 异常对象
     * @return 提示用户检查请求参数格式的错误信息
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public Result<Void> httpMessageNotReadableExceptionHandler(HttpMessageNotReadableException ex) {
        // 记录异常详情（例如 JSON 格式错误或类型转换失败）
        log.error("请求体解析异常:", ex);

        // 提取更友好的提示信息，例如类型不匹配或 JSON 语法错误
        String message = "请求参数格式错误，请检查JSON格式或数据类型";
        if (ex.getCause() != null) {
            String causeMsg = ex.getCause().getMessage();
            // 例如：Jackson解析错误时，提取关键信息
            if (causeMsg.contains("Cannot deserialize value of type")) {
                message = "参数类型不匹配：" + causeMsg.substring(0, Math.min(causeMsg.length(), 100));
            } else if (causeMsg.contains("Unexpected character")) {
                message = "JSON格式错误：" + causeMsg.substring(0, Math.min(causeMsg.length(), 50));
            }
        }

        return Result.error(StatusCode.PARAMS_ERROR.getCode(), message);
    }


    /**
     * 处理非法参数异常（通常由 Assert 或参数检查抛出）
     *
     * @param e 非法参数异常对象
     * @return 统一格式的参数错误响应
     */
    @ExceptionHandler(IllegalArgumentException.class)
    public Result<Void> illegalArgumentExceptionHandler(IllegalArgumentException e) {
        return Result.error(StatusCode.PARAMS_ERROR.getCode(), "请求参数验证失败" + e.getMessage());
    }
}
